<!-- 用户管理 -->
<template>
  <div class="app-container">
	
	<div class="app-layout">
		<div class="left">
			<DeptTree v-model="queryParams.deptId" @node-click="handleDeptSelect" />
		</div>
		<div class="right">
			<div class="pane">
				<div class="head" style="padding-right: 8px;">
					<div class="head-title">
						<span>用户列表</span>
						<template v-if="currentDept">
							<el-divider direction="vertical" />
							<span class="current-dept">{{ currentDept.name }}</span>
						</template>
					</div>
					<div style="flex: 1;"></div>
					<div style="width: 400px;">
						<el-button
						  v-hasPerm="['sys:user:add']"
						  type="primary"
						  icon="plus"
						  @click="handleOpenDialog()"
						  size="small"
						>
						  新增
						</el-button>
						<el-button
						  v-hasPerm="'sys:user:delete'"
						  type="danger"
						  icon="delete"
						  :disabled="selectIds.length === 0"
						  @click="handleDelete()"
						  size="small"
						>
						  删除
						</el-button>
						
<!-- 							<el-button
						  v-hasPerm="'sys:user:import'"
						  icon="upload"
						  @click="handleOpenImportDialog"
						>
						  导入
						</el-button>
											
						<el-button v-hasPerm="'sys:user:export'" icon="download" @click="handleExport">
						  导出
						</el-button> -->
					</div>
				</div>
				<div class="body">
					<div class="table-tool-bar">
						<div>
							    <el-input
							      v-model="queryParams.keywords"
							      style="width:320px"
							      placeholder="输入姓名、账号或手机号进行搜索"
							      class="input-with-select"
							    >
							      <template #append>
							        <el-button icon="search"  @click="handleQuery" />
							      </template>
							    </el-input>
						</div>
					</div>
					
					<div>
						<el-table v-loading="loading" border :data="pageData" height="calc(100vh - 260px)" @selection-change="handleSelectionChange">
						  <el-table-column type="selection" width="50" align="center" />
						  <el-table-column label="账号" width="150" align="left" prop="username" />
						  <el-table-column label="姓名"  align="left" prop="name" />
						  <el-table-column label="性别" width="80" align="center">
						    <template #default="scope">
						      <DictLabel v-model="scope.row.gender" code="gender" />
						    </template>
						  </el-table-column>
						  <el-table-column label="部门" width="220" align="left" prop="deptName" />
						  <el-table-column label="手机号码" align="left" prop="mobile" width="120" />
						  <el-table-column label="状态" align="center" prop="status" width="100">
						    <template #default="scope">
						      <el-tag :type="scope.row.status == '1' ? 'success' : 'info'">
						        {{ scope.row.status == '1' ? "正常" : "禁用" }}
						      </el-tag>
						    </template>
						  </el-table-column>
						  <el-table-column label="创建时间" align="left" prop="createTime" width="220" />
						  <el-table-column label="操作" fixed="right" width="220">
						    <template #default="scope">
						      <el-button
						        v-hasPerm="'sys:user:password:reset'"
						        type="primary"
						        icon="RefreshLeft"
						        size="small"
						        link
						        @click="hancleResetPassword(scope.row)"
						      >
						        重置密码
						      </el-button>
						      <el-button
						        v-hasPerm="'sys:user:edit'"
						        type="primary"
						        icon="edit"
						        link
						        size="small"
						        @click="handleOpenDialog(scope.row)"
						      >
						        编辑
						      </el-button>
						      <el-button
						        v-hasPerm="'sys:user:delete'"
						        type="danger"
						        icon="delete"
						        link
						        size="small"
						        @click="handleDelete(scope.row.id)"
						      >
						        删除
						      </el-button>
						    </template>
						  </el-table-column>
						</el-table>
						
						<div style="display: flex;justify-content: flex-end;align-items: center">
							<pagination
							  v-model:total="total"
							  v-model:page="queryParams.cur"
							  v-model:limit="queryParams.limit"
							  @pagination="handleQuery"
							/>
						</div>
						
					</div>
				</div>
			</div>
		</div>
	</div>  
	  
    <!-- 用户表单 -->
    <el-drawer
      v-model="dialog.visible"
      :title="dialog.title"
      append-to-body
      @close="handleCloseDialog"
	  :close-on-click-modal="false"
    >
      <el-form ref="userFormRef" :model="formData" :rules="rules" label-width="80px">
        <el-form-item label="用户名" prop="username">
          <el-input
            v-model="formData.username"
            :readonly="!!formData.id"
            placeholder="请输入用户名"
          />
        </el-form-item>

        <el-form-item label="用户姓名" prop="name">
          <el-input v-model="formData.name" placeholder="请输入用户姓名" />
        </el-form-item>

        <el-form-item label="所属部门" prop="deptId">
          <el-tree-select
            v-model="formData.deptId"
            placeholder="请选择所属部门"
            :data="deptOptions"
            filterable
            check-strictly
            :render-after-expand="false"
			:props="defaultProps"
          />
        </el-form-item>

        <el-form-item label="性别" prop="gender">
          <Dict v-model="formData.gender" code="gender" />
        </el-form-item>

        <el-form-item label="角色" prop="roleIds">
          <el-select v-model="formData.roleIds" multiple placeholder="请选择">
            <el-option
              v-for="item in roleOptions"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            />
          </el-select>
        </el-form-item>

        <el-form-item label="手机号码" prop="mobile">
          <el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
        </el-form-item>

        <el-form-item label="邮箱" prop="email">
          <el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
        </el-form-item>

        <el-form-item label="状态" prop="status">
          <el-switch
            v-model="formData.status"
            inline-prompt
            active-text="正常"
            inactive-text="禁用"
            :active-value="'1'"
            :inactive-value="'0'"
          />
        </el-form-item>
		
		<el-form-item label="备注" prop="remark">
		  <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" maxlength="250" />
		</el-form-item>
		
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确 定</el-button>
          <el-button @click="handleCloseDialog">取 消</el-button>
        </div>
      </template>
    </el-drawer>

    <!-- 用户导入 -->
    <UserImport v-model="importDialogVisible" @import-success="handleQuery()" />
  </div>
</template>

<script setup lang="ts">
import UserAPI, { UserForm, UserPageQuery, UserPageVO } from "@/api/system/user";

import DeptAPI from "@/api/system/dept";
import RoleAPI from "@/api/system/role";

import DeptTree from "./components/DeptTree.vue";
import UserImport from "./components/UserImport.vue";
import {
  recurOptions
} from "@/utils/TreeUtil";
defineOptions({
  name: "User",
  inheritAttrs: false,
});

const queryFormRef = ref(ElForm);
const userFormRef = ref(ElForm);
const defaultProps = {
  children: 'children',
  label: 'name',
  value:'id'
}
const queryParams = reactive<UserPageQuery>({
  cur: 1,
  limit: 10,
});

const pageData = ref<UserPageVO[]>();
const total = ref(0);
const loading = ref(false);

const dialog = reactive({
  visible: false,
  title: "新增用户",
});

const formData = reactive<UserForm>({
  status: '1',
});

const rules = reactive({
  username: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
  name: [{ required: true, message: "用户姓名不能为空", trigger: "blur" }],
  deptId: [{ required: true, message: "所属部门不能为空", trigger: "blur" }],
  roleIds: [{ required: true, message: "用户角色不能为空", trigger: "blur" }],
  email: [
    {
      pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
      message: "请输入正确的邮箱地址",
      trigger: "blur",
    },
  ],
  mobile: [
    {
      pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
      message: "请输入正确的手机号码",
      trigger: "blur",
    },
  ],
});

// 选中的用户ID
const selectIds = ref<string[]>([]);
// 部门下拉数据源
const deptOptions = ref<any[]>();
// 角色下拉数据源
const roleOptions = ref<any[]>();
// 导入弹窗显示状态
const importDialogVisible = ref(false);

// 当前选中的部门
const currentDept = ref<any>(null);

// 查询
function handleQuery() {
  loading.value = true;
  UserAPI.getPage(queryParams)
    .then((data) => {
      pageData.value = data.list;
      total.value = data.totalRow;
    })
    .finally(() => {
      loading.value = false;
    });
}

// 重置查询
function handleResetQuery() {
  queryFormRef.value.resetFields();
  queryParams.cur = 1;
  queryParams.deptId = undefined;
  queryParams.createTime = undefined;
  handleQuery();
}

// 选中项发生变化
function handleSelectionChange(selection: any[]) {
  selectIds.value = selection.map((item) => item.id);
}

// 重置密码
function hancleResetPassword(row: UserPageVO) {
  ElMessageBox.prompt("请输入用户【" + row.username + "】的新密码", "重置密码", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
  }).then(
    ({ value }) => {
      if (!value || value.length < 6) {
        ElMessage.warning("密码至少需要6位字符，请重新输入");
        return false;
      }
      UserAPI.resetPassword({
		  id:row.id, 
		  password:value
	  }).then(() => {
        ElMessage.success("密码重置成功，新密码是：" + value);
      });
    },
    () => {
      ElMessage.info("已取消重置密码");
    }
  );
}

/**
 * 打开弹窗
 *
 * @param id 用户ID
 */
async function handleOpenDialog(row?: any) {
  dialog.visible = true;
  roleOptions.value = await RoleAPI.getOptions();
  deptOptions.value = recurOptions(await DeptAPI.getOptions(),'-1');
  if (row) {
	dialog.title = "修改用户";
	if(row.userRoles){
		formData.roleIds=[];
		for(var userRole of row.userRoles){
			formData.roleIds?.push(userRole.roleId);
		}
	}
	 Object.assign(formData, { ...row });
  } else {
    dialog.title = "新增用户";
	formData.roleIds=[];
  }
}

// 关闭弹窗
function handleCloseDialog() {
  dialog.visible = false;
  userFormRef.value.resetFields();
  userFormRef.value.clearValidate();
  formData.id = undefined;
  formData.username=undefined;
  formData.name=undefined;
  formData.deptId=undefined;
  formData.certificatenum=undefined;
  formData.gender='3';
  formData.email=undefined;
  formData.mobile=undefined;
  formData.remark="";
  formData.status = '1';
  formData.roleIds=[]
}

// 提交用户表单（防抖）
const handleSubmit = useDebounceFn(() => {
  userFormRef.value.validate((valid: boolean) => {
    if (valid) {
      const userId = formData.id;
      loading.value = true;
      if (userId) {
        UserAPI.save({
			id:formData.id,
			deptId:formData.deptId,
			username:formData.username,
			name:formData.name,
			status:formData.status,
			certificatenum:formData.certificatenum,
			mobile:formData.mobile,
			gender:formData.gender,
			remark:formData.remark,
			roleIds:JSON.stringify(formData.roleIds)
		})
          .then(() => {
            ElMessage.success("修改用户成功");
            handleCloseDialog();
            handleResetQuery();
          })
          .finally(() => (loading.value = false));
      } else {
        UserAPI.save({
			id:formData.id,
			deptId:formData.deptId,
			username:formData.username,
			name:formData.name,
			status:formData.status,
			certificatenum:formData.certificatenum,
			mobile:formData.mobile,
			gender:formData.gender,
			remark:formData.remark,
			roleIds:JSON.stringify(formData.roleIds)
		})
          .then(() => {
            ElMessage.success("新增用户成功");
            handleCloseDialog();
            handleResetQuery();
          })
          .finally(() => (loading.value = false));
      }
    }
  });
}, 1000);

/**
 * 删除用户
 *
 * @param id  用户ID
 */
function handleDelete(id?: string) {
  const userIds = [id || selectIds.value].join(",");
  if (!userIds) {
    ElMessage.warning("请勾选删除项");
    return;
  }

  ElMessageBox.confirm("确认删除用户?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(
    function () {
      loading.value = true;
      UserAPI.deleteByIds(userIds)
        .then(() => {
          ElMessage.success("删除成功");
          handleResetQuery();
        })
        .finally(() => (loading.value = false));
    },
    function () {
      ElMessage.info("已取消删除");
    }
  );
}

// 打开导入弹窗
function handleOpenImportDialog() {
  importDialogVisible.value = true;
}

// 导出用户
function handleExport() {
  UserAPI.export(queryParams).then((response: any) => {
    const fileData = response.data;
    const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]);
    const fileType =
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";

    const blob = new Blob([fileData], { type: fileType });
    const downloadUrl = window.URL.createObjectURL(blob);

    const downloadLink = document.createElement("a");
    downloadLink.href = downloadUrl;
    downloadLink.download = fileName;

    document.body.appendChild(downloadLink);
    downloadLink.click();

    document.body.removeChild(downloadLink);
    window.URL.revokeObjectURL(downloadUrl);
  });
}

// 处理部门选择
const handleDeptSelect = (dept: any) => {
  currentDept.value = dept;
  handleQuery();
};

onMounted(() => {
  handleQuery();
});
</script>

<style lang="scss" scoped>
	.left{
		width: 320px;
		margin-right: 10px;
	}
	.right{
		width: calc(100% - 330px);
	}
	.table-tool-bar{
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 5px;
	}
	.head-title {
		display: flex;
		align-items: center;
		
		.current-dept {
			color: var(--el-color-primary);
			font-weight: bold;
		}
	}
	:deep(.el-divider--vertical) {
		margin: 0 8px;
		height: 14px;
	}
	:deep(.el-table th.el-table__cell) {
		/* background-color: #fafafa; */
		background-color: #eee;
		background-image: url();
		background-image: -webkit-linear-gradient(top, #f2f2f2 0, #fafafa 100%);
		background-image: -moz-linear-gradient(top, #f2f2f2 0, #fafafa 100%);
		background-image: -o-linear-gradient(top, #f2f2f2 0, #fafafa 100%);
		background-image: linear-gradient(to bottom, #f2f2f2 0, #fafafa 100%);
		font-size: 12px;
	}
</style>

